package com.newegg.sshd;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.SocketAddress;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

import org.apache.sshd.common.AttributeRepository;
import org.apache.sshd.common.io.IoAcceptor;
import org.apache.sshd.common.io.IoConnector;
import org.apache.sshd.common.io.IoServiceEventListener;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.auth.AsyncAuthException;
import org.apache.sshd.server.auth.keyboard.DefaultKeyboardInteractiveAuthenticator;
import org.apache.sshd.server.auth.password.PasswordAuthenticator;
import org.apache.sshd.server.auth.password.PasswordChangeRequiredException;
import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
import org.apache.sshd.server.channel.ChannelSession;
import org.apache.sshd.server.command.Command;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.shell.ShellFactory;
import org.slf4j.Logger;

public class SSHD {
	static Logger logger = org.slf4j.LoggerFactory.getLogger(SSHD.class);
	
	public static void main(String[] args) throws IOException, InterruptedException, NoSuchAlgorithmException {
		final SshServer sshd = SshServer.setUpDefaultServer();
		sshd.setPort(42222);
		
        File keyPairFile = new File(".ssh",".keypair.ser");
        File publicKeyFile = new File(".ssh",".knownhosts");
        if(!keyPairFile.exists()) {
        	keyPairFile.getParentFile().mkdirs();
            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
            KeyPair keyPair = generator.generateKeyPair();
            ObjectOutputStream outs = new ObjectOutputStream(new FileOutputStream(keyPairFile));
            outs.writeObject(keyPair);
            outs.flush();
            outs.close();
        }
        sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(keyPairFile.toPath()));
        sshd.setPublickeyAuthenticator(new PublickeyAuthenticator() {
            public boolean authenticate(String s, PublicKey publicKey, ServerSession serverSession) {
                byte[] key = publicKey.getEncoded();
                serverSession.getProperties().put("__PUBKEY__", key);
                List<byte[]> publicKeyList = getPublicKeys(publicKeyFile);
                boolean isEqual = false;
                for (byte[] bytes : publicKeyList) {
                    if (bytes.length == key.length) {
                        isEqual = true;
                        for (int i = 0; i < bytes.length; ++i) {
                            if (bytes[i] != key[i]) {
                                isEqual = false;
                                break;
                            }
                        }
                        if (isEqual) {
                            break;
                        }
                    }
                }
                return isEqual;
            }
        });
        
		sshd.setKeyboardInteractiveAuthenticator(DefaultKeyboardInteractiveAuthenticator.INSTANCE);
		sshd.setPasswordAuthenticator(new PasswordAuthenticator() {
			public boolean authenticate(String username, String password, ServerSession session) throws PasswordChangeRequiredException, AsyncAuthException {
				if("root".equals(username) && "root".equals(password)) {
					session.setUsername(username);
					return true;
				}
				return false;
			}
		});
		sshd.setIoServiceEventListener(new IoServiceEventListener() {
			@Override
			public void connectionEstablished(IoConnector connector, SocketAddress local, AttributeRepository context, SocketAddress remote) throws IOException {
				logger.info("新连接connectionEstablished：" + remote.toString());
			}
			@Override
			public void abortEstablishedConnection(IoConnector connector, SocketAddress local, AttributeRepository context, SocketAddress remote, Throwable reason)throws IOException {
				logger.info("新连接abortEstablishedConnection：" + remote.toString());
		    }
			@Override
			public void connectionAccepted(IoAcceptor acceptor, SocketAddress local, SocketAddress remote, SocketAddress service) throws IOException {
				logger.info("新连接connectionAccepted：" + remote.toString());
		    }
			public void abortAcceptedConnection(IoAcceptor acceptor, SocketAddress local, SocketAddress remote, SocketAddress service, Throwable reason)throws IOException {
				logger.info("新连接abortAcceptedConnection：" + remote.toString());
		    }
		});
		sshd.setShellFactory(new ShellFactory() {
			@Override
			public Command createShell(ChannelSession channel) throws IOException {
				ServerSession session = channel.getSession();
				logger.info("用户登录成功：" + session.getClientAddress().toString());
				return new BashCommand(channel);
			}
		});
		sshd.start();
		logger.info("开启服务：" + 42222);
		while (true) { Thread.sleep(1000); }
	}

	 private static List<byte[]> getPublicKeys(File publicKeyFile) {
         List<byte[]> publicKeyList = new ArrayList<>();
         try {
             if(!publicKeyFile.exists()) {
                 publicKeyFile.createNewFile();
             }
             BufferedReader reader = new BufferedReader(new FileReader(publicKeyFile));
             String line = null;
             Base64.Decoder decoder = Base64.getDecoder();
             while(null != (line = reader.readLine())) {
                 publicKeyList.add(decoder.decode(line));
             }
             reader.close();
         } catch (Exception ex) {
         }
         return publicKeyList;
     }
}
